home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cocktail / estra.lha / estra / src / Automaton.mi < prev    next >
Text File  |  1992-08-18  |  11KB  |  510 lines

  1. (* $Id: Automaton.mi,v 2.1 1992/01/30 14:26:17 grosch rel $ *)
  2.  
  3. IMPLEMENTATION MODULE Automaton;
  4.  
  5. FROM DynArray    IMPORT    MakeArray, ExtendArray, ReleaseArray;
  6. FROM Errors    IMPORT    ERROR;
  7. FROM IO        IMPORT    tFile;
  8. FROM Memory    IMPORT    Alloc;
  9. FROM Queues    IMPORT    tQueue, Length, GetElement;
  10. FROM System    IMPORT    Write;
  11. FROM SYSTEM    IMPORT    ADR, TSIZE;
  12.  
  13. (* AUTO_ *)
  14. FROM Info    IMPORT    WriteIdentSet;
  15. FROM IO        IMPORT    StdOutput;
  16. FROM Queues    IMPORT    MakeQueue, ReleaseQueue, Append, ClearLast;
  17. FROM StdIO    IMPORT    WriteS, WriteI, WriteNl;
  18. FROM Sets    IMPORT    tSet, MakeSet, ReleaseSet, Include,
  19.             Exclude, IsElement, WriteSet, AssignEmpty;
  20. (* _AUTO *)
  21.  
  22. CONST
  23.   NoState = -1;
  24.   StartState = 0;
  25.   InitCombSize = 100;
  26.  
  27. TYPE
  28.   tState = INTEGER;
  29.  
  30.   tStateTable = POINTER TO ARRAY [0..1000] OF tState;
  31.  
  32.   tComb = POINTER TO ARRAY [0..1000] OF INTEGER;
  33.  
  34.   tTransition = POINTER TO tTransitionR;
  35.  
  36.   tTransitionR =
  37.     RECORD
  38.       Input: INTEGER;
  39.       Target: tState;
  40.       Next: tTransition;
  41.     END;
  42.  
  43.   tStateR =
  44.     RECORD
  45.       Trans: tTransition;
  46.       MainState: tState;
  47.     END;
  48.  
  49.   tAutomaton =
  50.     RECORD
  51.       StopStates: tState;
  52.       LastState: tState;
  53.       MaxInput: INTEGER;
  54.       TransitionTable: POINTER TO ARRAY [0..1000] OF tStateR;
  55.       TableSize: INTEGER; TableSizeL: LONGINT;
  56.       IndexArray: POINTER TO ARRAY [0..1000] OF INTEGER;
  57.       IndexArraySize: LONGINT;
  58.     END;
  59.  
  60. VAR
  61.   Automaton: tAutomaton;
  62.   Comb: tComb;
  63.   CombSizeL: LONGINT;
  64.   CombSize: INTEGER;
  65.   CombCount: INTEGER;
  66.  
  67. PROCEDURE BeginAutomaton    (stopstates: INTEGER; maxinput: INTEGER);
  68.   VAR
  69.     state: tState;
  70.   BEGIN
  71.     WITH Automaton DO
  72.       StopStates := stopstates;
  73.       LastState := stopstates;
  74.       MaxInput := maxinput;
  75.       TableSizeL := 4 * stopstates + 4;
  76.       MakeArray (TransitionTable, TableSizeL, TSIZE (tStateR));
  77.       TableSize := TableSizeL;
  78.       FOR state := 0 TO TableSize - 1 DO
  79.     TransitionTable^[state].Trans := NIL;
  80.     TransitionTable^[state].MainState := NoState;
  81.       END;
  82.     END;
  83.   END BeginAutomaton;
  84.  
  85. (* -------------------- *)
  86.  
  87. PROCEDURE DefineTransition    (path: tQueue; stop: INTEGER);
  88.   VAR
  89.     state: tState;
  90.     input, length, pos: INTEGER;
  91.  
  92.   BEGIN
  93.     state := StartState;
  94.     pos := 0;
  95.     length := Length (path);
  96.     LOOP
  97.       INC (pos);
  98.       input := INTEGER (GetElement (path, pos));
  99.       IF pos = length THEN EXIT; END;
  100.       state := MakeTarget (state, input);
  101.     END;
  102.     SetTarget (state, input, stop);
  103.   END DefineTransition;
  104.  
  105. PROCEDURE NewState (): tState;
  106.   VAR
  107.     state, size: tState;
  108.   BEGIN
  109.     WITH Automaton DO
  110.       INC (LastState);
  111.       IF LastState >= TableSize THEN
  112.     ExtendArray (TransitionTable, TableSizeL, TSIZE (tStateR));
  113.       END;
  114.       size := TableSizeL;
  115.       FOR state := TableSize TO size - 1 DO
  116.     TransitionTable^[state].Trans := NIL;
  117.     TransitionTable^[state].MainState := NoState;
  118.       END;
  119.       TableSize := TableSizeL;
  120.       RETURN LastState;
  121.     END;
  122.   END NewState;
  123.  
  124. PROCEDURE MakeTarget (state: tState; input: INTEGER): tState;
  125.   VAR
  126.     t: POINTER TO tTransition;
  127.   BEGIN
  128.     t := ADR (Automaton.TransitionTable^[state].Trans);
  129.     LOOP
  130.       IF t^ = NIL THEN EXIT END;
  131.       IF t^^.Input = input THEN
  132.     RETURN (t^^.Target);
  133.       END;
  134.       t := ADR (t^^.Next);
  135.     END;
  136.     t^ := Alloc (TSIZE (tTransitionR));
  137.     t^^.Input := input;
  138.     t^^.Target := NewState ();
  139.     t^^.Next := NIL;
  140.     RETURN t^^.Target;
  141.   END MakeTarget;
  142.  
  143. PROCEDURE SetTarget (state: tState; input: INTEGER; stop: tState);
  144.   VAR
  145.     t: POINTER TO tTransition;
  146.   BEGIN
  147.     t := ADR (Automaton.TransitionTable^[state].Trans);
  148.     LOOP
  149.       IF t^ = NIL THEN EXIT END;
  150.       IF t^^.Input = input THEN
  151.     ERROR ('Automaton.SetTarget: already defined');
  152.       END;
  153.       t := ADR (t^^.Next);
  154.     END;
  155.     t^ := Alloc (TSIZE (tTransitionR));
  156.     t^^.Input := input;
  157.     t^^.Target := stop;
  158.     t^^.Next := NIL;
  159.   END SetTarget;
  160.  
  161. (* -------------------- *)
  162.  
  163. PROCEDURE ReduceAutomaton;
  164.   VAR
  165.     actual, state: tState;
  166.     input: INTEGER;
  167.     T: tStateTable;
  168.     s: LONGINT;
  169.   BEGIN
  170.     WITH Automaton DO
  171.       s := MaxInput + 1;
  172.       MakeArray (T, s, TSIZE (tState));
  173.       FOR actual := LastState - 1 TO StopStates + 1 BY -1 DO
  174.     DefineTable (T, actual);
  175.     FOR state := actual + 1 TO LastState DO
  176.       IF Compatible (T, state) THEN
  177.         Melt (actual, state, T);
  178.       END;
  179.     END;
  180.       END;
  181.       ReleaseArray (T, s, TSIZE (tState));
  182.     END;
  183.   END ReduceAutomaton;
  184.  
  185. PROCEDURE DefineTable (T: tStateTable; state: tState);
  186.   VAR
  187.     input: tState;
  188.     t: tTransition;
  189.   BEGIN
  190.     WITH Automaton DO
  191.       FOR input := 0 TO MaxInput DO
  192.         T^ [input] := NoState;
  193.       END;
  194.       t := TransitionTable^[state].Trans;
  195.       WHILE t # NIL DO
  196.     T^ [t^.Input] := MainState (t^.Target);
  197.     t := t^.Next;
  198.       END;
  199.     END;
  200.   END DefineTable;
  201.  
  202. PROCEDURE Compatible (T: tStateTable; state: tState): BOOLEAN;
  203.   VAR
  204.     t: tTransition;
  205.   BEGIN
  206.     WITH Automaton DO
  207.       IF TransitionTable^[state].MainState # NoState THEN
  208.     RETURN FALSE;        (* only main states may be compatible *)
  209.       END;
  210.       t := TransitionTable^[state].Trans;
  211.       WHILE t # NIL DO
  212.     IF (T^[t^.Input] # NoState)
  213.      & (MainState (T^[t^.Input]) # MainState (t^.Target)) THEN
  214.       RETURN FALSE;
  215.     END;
  216.     t := t^.Next;
  217.       END;
  218.       RETURN TRUE;
  219.     END;
  220.   END Compatible;
  221.  
  222. PROCEDURE Melt (actual, state: tState; T: tStateTable);
  223.   VAR
  224.     t: tTransition;
  225.     input: INTEGER;
  226.     target: tState;
  227.   BEGIN
  228.     WITH Automaton DO
  229.       t := TransitionTable^[state].Trans;
  230.       WHILE t # NIL DO
  231.     input := t^.Input;
  232.     IF T^ [input] = NoState THEN        (* transition must be defined *)
  233.       target := MainState (t^.Target);
  234.       T^ [input] := target;
  235.       SetTarget (actual, input, target);
  236.     END;
  237.     t := t^.Next;
  238.       END;
  239.       TransitionTable^[state].MainState := actual;
  240.     END;
  241.   END Melt;
  242.  
  243. (* -------------------- *)
  244.  
  245. PROCEDURE MakeComb;
  246.   VAR 
  247.     state, main: tState;
  248.     index: INTEGER;
  249.   BEGIN
  250.     CombCount := -1;
  251.     CombSize := 0;
  252.     WITH Automaton DO
  253.       FOR state := StartState TO StopStates DO
  254.     IndexArray^[state] := state;
  255.       END;
  256.       FOR state := StopStates + 1 TO LastState DO
  257.     main := TransitionTable^[state].MainState;
  258.     IF main = NoState THEN
  259.       index := 0;
  260.       WHILE NOT Fits (index, state) DO;
  261.         INC (index);
  262.       END;
  263.       Embed (index, state);
  264.     ELSE
  265.       index := IndexArray^[main];
  266.     END;
  267.     IndexArray^[state] := index;
  268.       END;
  269.       FOR index := 0 TO CombCount DO
  270.         state := Comb^[index];
  271.     IF state > StopStates THEN
  272.       Comb^[index] := IndexArray^[state]
  273.     END;
  274.       END;
  275.     END;
  276.   END MakeComb;
  277.  
  278. PROCEDURE Fits (index: INTEGER; state: tState): BOOLEAN;
  279.   VAR
  280.     t: tTransition;
  281.     i: INTEGER;
  282.     old, j: INTEGER;
  283.   BEGIN
  284.     t := Automaton.TransitionTable^[state].Trans;
  285.     WHILE t # NIL DO
  286.       i := index + t^.Input;
  287.       IF i > CombCount THEN
  288.     WHILE i >= CombSize DO
  289.       old := CombSize;
  290.       IF CombSize = 0 THEN
  291.         CombSizeL := InitCombSize;
  292.         MakeArray (Comb, CombSizeL, TSIZE (INTEGER));
  293.       ELSE
  294.         ExtendArray (Comb, CombSizeL, TSIZE (INTEGER));
  295.       END;
  296.       CombSize := CombSizeL;
  297.       FOR j := old TO CombSize - 1 DO
  298.         Comb^ [j] := NoState;
  299.       END;
  300.     END;
  301.     CombCount := i;
  302.       END;
  303.       IF (Comb^[i] # NoState) & (Comb^[i] # t^.Target) THEN
  304.     RETURN FALSE;
  305.       END;
  306.       t := t^.Next;
  307.     END;
  308.     RETURN TRUE;
  309.   END Fits;
  310.  
  311. PROCEDURE Embed (index: INTEGER; state: tState);
  312.   VAR
  313.     t: tTransition;
  314.   BEGIN
  315.     t := Automaton.TransitionTable^[state].Trans;
  316.     WHILE t # NIL DO
  317.       Comb^[index + t^.Input] := t^.Target;
  318.       t := t^.Next;
  319.     END;
  320.   END Embed;
  321.  
  322. (* -------------------- *)
  323.  
  324. PROCEDURE CloseAutomaton    (f: tFile; VAR CombSize: INTEGER);
  325.   BEGIN
  326.     ReduceAutomaton;
  327.     WITH Automaton DO
  328.       IndexArraySize := LastState + 1;
  329.       MakeArray (IndexArray, IndexArraySize, TSIZE (INTEGER));
  330.     END;
  331.     MakeComb;
  332.     OutputComb (f);
  333.     CombSize := CombCount;
  334.   END CloseAutomaton;
  335.  
  336. PROCEDURE OutputComb (f: tFile);
  337.   VAR
  338.     i: INTEGER;
  339.   BEGIN
  340.     i := Write (f, Comb, (1 + CombCount) * TSIZE (INTEGER));
  341.   END OutputComb;
  342.  
  343.  
  344. PROCEDURE ReleaseAutomaton;
  345.   BEGIN
  346.     WITH Automaton DO
  347.       ReleaseArray (IndexArray, IndexArraySize, TSIZE (INTEGER));
  348.     END;
  349.   END ReleaseAutomaton;
  350.  
  351. (* -------------------- *)
  352. PROCEDURE StartIndex        (input: INTEGER): INTEGER;
  353.   VAR
  354.     trans: tTransition;
  355.   BEGIN
  356.     WITH Automaton DO
  357.       trans := TransitionTable^[StartState].Trans;
  358.       LOOP
  359.     IF trans = NIL THEN EXIT END;
  360.     IF trans^.Input = input THEN
  361.       RETURN IndexArray^[trans^.Target];
  362.     END;
  363.     trans := trans^.Next;
  364.       END;
  365.       ERROR ('Automaton.StartIndex: not defined');
  366.     END;
  367.   END StartIndex;
  368.  
  369. PROCEDURE MainState (state: tState): tState;
  370.   BEGIN
  371.     WITH Automaton DO
  372.       WHILE (state > StopStates)
  373.       & (TransitionTable^[state].MainState # NoState) DO
  374.     state := TransitionTable^[state].MainState;
  375.       END;
  376.       RETURN state;
  377.     END;
  378.   END MainState;
  379.  
  380. (* -------------------- *)
  381.  
  382.  
  383. (* AUTO_ *)
  384. PROCEDURE WriteFunction;
  385.   VAR
  386.     q: tQueue;
  387.   BEGIN
  388.     MakeQueue (q);
  389.     WriteTrans (StartState, q);
  390.     ReleaseQueue (q);
  391.   END WriteFunction;
  392.  
  393. PROCEDURE WriteTrans (state: tState; VAR q: tQueue);
  394.   VAR
  395.     done: tSet;
  396.     trans, t: tTransition;
  397.     inputs: tSet;
  398.     in: POINTER TO tSet;
  399.     pos: INTEGER;
  400.     target: tState;
  401.   BEGIN
  402.     WITH Automaton DO
  403.       MakeSet (done, LastState);
  404.       MakeSet (inputs, MaxInput);
  405.       Append (q, ADR (inputs));
  406.       trans := TransitionTable^[state].Trans;
  407.       LOOP
  408.         IF trans = NIL THEN EXIT END;
  409.     target := MainState (trans^.Target);
  410.     IF NOT IsElement (target, done) THEN
  411.       AssignEmpty (inputs);
  412.       Include (inputs, trans^.Input);
  413.       t := trans^.Next;
  414.       WHILE t # NIL DO
  415.         IF MainState (t^.Target) = target THEN
  416.           Include (inputs, t^.Input);
  417.         END;
  418.         t := t^.Next;
  419.       END;
  420.       IF target > StopStates THEN
  421.         WriteTrans (target, q);
  422.       ELSE
  423.         in := GetElement (q, 1);
  424.         WriteIdentSet (StdOutput, in^);
  425.         WriteS (' ');
  426.         FOR pos := 2 TO Length (q) DO
  427.           in := GetElement (q, pos);
  428.           WriteSet (StdOutput, in^);
  429.           WriteS (' ');
  430.         END;
  431.         WriteS (' = ');
  432.         WriteI (target, 1);
  433.         WriteNl;
  434.       END;
  435.       Include (done, target);
  436.     END;
  437.     trans := trans^.Next;
  438.       END;
  439.       ClearLast (q);
  440.       ReleaseSet (inputs);
  441.       ReleaseSet (done);
  442.     END;
  443.   END WriteTrans;
  444.  
  445. PROCEDURE WriteAutomaton;
  446.   VAR
  447.     state: tState;
  448.   BEGIN
  449.     WriteS ('Automaton');
  450.     WriteNl;
  451.     FOR state := 0 TO Automaton.LastState DO
  452.       WriteState (state);
  453.     END;
  454.     WriteNl;
  455.   END WriteAutomaton;
  456.  
  457. PROCEDURE WriteState (state: tState);
  458.   VAR
  459.     t: tTransition;
  460.     m: tState;
  461.   BEGIN
  462.  
  463.     m := Automaton.TransitionTable^[state].MainState;
  464.     IF m # NoState THEN
  465.       WriteI (state, 3);
  466.       WriteS (' -> ');
  467.       WriteI (m, 3);
  468.       WriteNl;
  469.     ELSE
  470.       t := Automaton.TransitionTable^[state].Trans;
  471.       IF t # NIL THEN
  472.     WriteI (state, 3);
  473.     WHILE t # NIL DO
  474.       WriteS ('  (');
  475.       WriteI (t^.Input, 1);
  476.       WriteS (', ');
  477.       WriteI (t^.Target, 1);
  478.       WriteS (')');
  479.       t := t^.Next;
  480.     END;
  481.     WriteNl;
  482.       END;
  483.     END;
  484.   END WriteState;
  485.  
  486. PROCEDURE WriteComb;
  487.   VAR
  488.     index: INTEGER;
  489.   BEGIN
  490.     WriteS ('Comb');
  491.     WriteNl;
  492.     WriteS ('       ');
  493.     FOR index := 0 TO 9 DO
  494.       WriteI (index, 5);
  495.     END;
  496.     FOR index := 0 TO CombCount DO
  497.       IF index MOD 10 = 0 THEN
  498.     WriteNl;
  499.     WriteI (index, 5);
  500.     WriteS ('  ');
  501.       END;
  502.       WriteI (Comb^[index], 5);
  503.     END;
  504.     WriteNl;
  505.     WriteNl;
  506.   END WriteComb;
  507. (* _AUTO *)
  508.  
  509. END Automaton.
  510.